﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;

namespace huqiang.Collections
{
    public class LockBuffer<T>where T:class
    {
        T[] buffer;
        int max;
        int point;
        public int Max { get => max; }
        public int Count { get => point; }

        SpinLock spin = new SpinLock();
        public T this[int index] { 
            get 
            {
                T r = null;
                if (index < 0)
                    return r;
                bool gotLock = false;
                try
                {
                    spin.Enter(ref gotLock);
                    if (index < point)
                        r = buffer[index];
                }
                finally
                {
                    if (gotLock)
                        spin.Exit();
                }
                return r;
            }
            set 
            {
                if (index < 0)
                    return;
                bool gotLock = false;
                try
                {
                    spin.Enter(ref gotLock);
                    if (index < point)
                        buffer[index] = value;
                }
                finally
                {
                    if (gotLock)
                        spin.Exit();
                }
            } 
        }
        public LockBuffer(int len)
        {
            max = len;
            buffer = new T[len];
        }
        public void Add(T item)
        {
            if (point >= max)
                return;
            bool gotLock = false;
            try
            {
                spin.Enter(ref gotLock);
                buffer[point]=item;
                point++;
            }
            finally
            {
                if (gotLock) 
                    spin.Exit();
            }
        }
        public void Remove(T item)
        {
            bool gotLock = false;
            try
            {
                spin.Enter(ref gotLock);
                for (int i = 0; i < point; i++)
                {
                    if (buffer[i] == item)
                    {
                        point--;
                        buffer[i] = buffer[point];
                        buffer[point] = null;
                        break;
                    }
                }
            }
            finally
            {
                if (gotLock)
                    spin.Exit();
            }
        }
        public void RemoveAt(int index)
        {
            bool gotLock = false;
            try
            {
                spin.Enter(ref gotLock);
                if (index >= 0 & index < point)
                {
                    point--;
                    buffer[index] = buffer[point];
                    buffer[point] = null;
                }
#if DEBUG
                else throw new Exception("index out of range");
#endif
            }
            finally
            {
                if (gotLock)
                    spin.Exit();
            }
        }
        public T Find(Func<T,bool> compare)
        {
            T r = null;
            bool gotLock = false;
            try
            {
                spin.Enter(ref gotLock);
                for (int i = 0; i < point; i++)
                {
                    if (compare(buffer[i]))
                    {
                        r = buffer[i];
                        break;
                    }
                }
            }
            finally
            {
                if (gotLock)
                    spin.Exit();
            }
            return r;
        }
        public void Execute(Action<T> action)
        {
            bool gotLock = false;
            try
            {
                spin.Enter(ref gotLock);
                for (int i = 0; i < point; i++)
                {
                    action(buffer[i]);
                }
            }
            finally
            {
                if (gotLock)
                    spin.Exit();
            }
        }
        public void Clear()
        {
            bool gotLock = false;
            try
            {
                spin.Enter(ref gotLock);
                for (int i = 0; i < point; i++)
                {
                    buffer[i] = null;
                }
                point = 0;
            }
            finally
            {
                if (gotLock)
                    spin.Exit();
            }
        }
    }
}
